import os
import httpx
import json
import asyncio

# async_model_request 协程异步函数（参数 user_input，该参数用于传递用户输入的内容给 OpenAI AP）
# async with 语句创建一个异步的 httpx 客户端，（httpx向 OpenAI API 发起请求）
async def async_model_request(user_input):
    async with httpx.AsyncClient(proxy="http://127.0.0.1:7890") as client:
        response = await client.post(
            "https://api.openai.com/v1/chat/completions",
            headers={
                "Content-Type": "application/json",
                "Authorization": f"Bearer xxxxxxxx",
                # "Authorization": f"Bearer { os.environ['OPENAI_API_KEY'] }",
            },
            json={
                "model": "gpt-4o-mini",
                "messages": [
                    {
                        "role": "developer",
                        "content": "You are a helpful assistant."
                    },
                    {
                        "role": "user",
                        "content": user_input
                    }
                ]
            }
        )
        print(response.status_code)
        print(response.content)
        if response.status_code == 200:
            response_data = json.loads(response.content.decode())
            print(response_data)
            print(response_data["choices"][0]["message"])
        else:
            response_data = json.loads(response.content.decode())
            print(response_data["error"])

"""
（1）场景一：执行一个线程对象：async_model_request 函数是向 OpenAI 的聊天补全 API 发送请求的异步函数（结合之前代码），传入 "Hello" 后，
会在异步环境下请求 OpenAI 模型，获取模型基于输入给出的回复，同时打印请求响应的状态码、内容等信息 ，根据状态码判断请求是否成功并做相应处理
"""
try:
    print(asyncio.run(async_model_request("Hello"))) # 执行一个线程对象
except RuntimeError as e:
    print(e)
    print(e.status_code)
    print(e.error_content)

"""
（2）场景二：执行多个线程对象
"""
async def concurrent_request(question_list):
    tasks = []
    for question in question_list:
        tasks.append(asyncio.create_task(async_model_request(question)))  #创建任务过程：创建单个协程对象 asyncio.create_task(执行哪个异步函数)
    await asyncio.gather(*tasks)  # 协程组（回收所有的任务）：await asyncio.gather（[task1,task2,task3,task4...]）

asyncio.run(concurrent_request([
    "Hello",
    "Who are you?",
    "How are you?",
    "How is the weather today?",
    "Are you an AI or a human being?",
]))

"""
给批量请求加入批次处理等待和容错；
"""
# 定义了一个异步函数 concurrent_request()
    # question_list 是包含要发送给模型的问题列表；
    # batch_length 用于指定每次并发请求的问题数量，默认值为 2；
    # interval 表示每次批量请求后等待的时间间隔，默认值为 1 秒
async def concurrent_request2(question_list, batch_length=2, interval=1):
    all_results = [] #存储所有问题的请求结果(问题和对应处理结果（可能是正常回复或异常）)
    error_tasks = [] #录请求过程中出现运行时错误的任务(问题和对应 RuntimeError 异常)
    start_pos = 0    # 当前处理批次在 question_list 中的起始位置，初始化为 0
    # 根据 batch_length 和问题列表长度确定当前批次的结束位置
    end_pos = batch_length if batch_length < len(question_list) else len(question_list) - 1
    while start_pos < len(question_list): # 只要 start_pos 小于问题列表长度,就进入循环
        current_batch = question_list[start_pos:end_pos] # 获取当前批次的问题列表切片
        current_tasks = [] # 用于存放当前批次要并发执行的任务
        for question in current_batch: # 遍历当前批次的每个问题
            current_tasks.append(asyncio.create_task(async_model_request(question))) #为每个问题创建一个异步任务，调用 async_model_request 函数（结合之前代码推测是向模型发送请求的异步函数 ）并将任务添加到 current_tasks 列表
        results = await asyncio.gather(*current_tasks, return_exceptions=True) #并发运行当前批次的所有任务，并等待它们完成
        # return_exceptions = True 表示如果任务执行过程中出现异常，会将异常作为结果返回，而不是直接抛出
        # 处理结果：
        for index, result in enumerate(results): # 遍历任务执行结果
            if isinstance(result, RuntimeError): #将出现错误的问题和对应的异常添加到 error_tasks 列表
                error_tasks.append((current_batch[index], result))
            all_results.append((current_batch[index], result)) # 将每个问题及其对应的结果（不管是正常回复还是异常）添加到 all_results 列表
        start_pos += batch_length # 更新下一批次的起始和结束位置
        end_pos += batch_length
        await asyncio.sleep(interval) # 等待指定的时间间隔，避免过于频繁地向服务器发送请求
    print(all_results)
    print(error_tasks)

# 启动整个批量并发请求流程：
asyncio.run(concurrent_request2([
    "Hello",
    "Who are you?",
    "How are you?",
    "How is the weather today?",
    "Are you an AI or a human being?",
], 2))



"""
多轮对话
"""
import os
import httpx
import json

def request_model(messages):
    response = httpx.post(
        "https://api.openai.com/v1/chat/completions",
        headers={
            "Content-Type": "application/json",
            "Authorization": f"Bearer { os.environ['OPENAI_API_KEY'] }",
        },
        json={
            "model": "gpt-4o-mini",
            "messages": messages,
        },
        proxy="http://127.0.0.1:7890",
    )
    response_data = json.loads(response.content.decode())
    return response_data["choices"][0]["message"]["content"]

messages = []
while True:
    user_input = input("[User]:")
    if user_input == "#exit":
        break
    messages.append({"role": "user", "content": user_input})
    reply = request_model(messages)
    print(f"[Assistant]: {reply}")
    messages.append({"role": "assistant", "content": reply})











